#pragma once

#include <boost/operators.hpp>
#include <boost/shared_array.hpp>
#include <boostext/exception.hpp>

#include "ReflectionElement.hpp"




/**
 * The StaticReflection structure holds a reference to a StaticReflectionElement table that defines
 * the layout of a structure.
 */
class ENGINE_CORE_API StaticReflection
	: boost::equality_comparable< StaticReflection
	>
{
public:

	typedef StaticReflectionElement*   ReflectionTable;

private:

	const StaticReflectionElement*   m_table;
	std::size_t   m_elements;
	std::size_t   m_totalSize;

public:

	/**
	 * Create a StaticReflection class from a table and a complete size.
	 */
	StaticReflection(const StaticReflectionElement* table, std::size_t totalSize);



	/**
	 * Get the number of elements in this StaticReflection.
	 */
	std::size_t elements() const;

	/**
	 * Get the total size of the structure in bytes.
	 */
	std::size_t totalSize() const;

	/**
	 * Get access to an element by its index in the reflection table.
	 */
	const StaticReflectionElement& operator[](std::size_t index) const;



	/**
	 * Test if this StaticReflection object is equal to another one.
	 * Does a shallow-comparison, only comparing the pointers to the table.
	 */
	bool operator==(const StaticReflection& that) const;
};
///////////////////////////////////////////////////////////////////////////////////////////////////




class ENGINE_CORE_API Reflection
	: boost::equality_comparable< Reflection
	, boost::equality_comparable< Reflection, StaticReflection
	> >
{
public:

	typedef std::vector<ReflectionElement>   LayoutArray;

private:

	#pragma warning (push)
	#pragma warning (disable: 4251)
	LayoutArray   m_table;
	std::size_t   m_totalSize;
	#pragma warning (pop)

public:

	/**
	 * Create a Reflection for a structure.
	 */
	Reflection(std::size_t totalSize, std::size_t elements);



	/**
	 * Get the number of elements in this reflection.
	 */
	std::size_t elements() const;

	/**
	 * Get the size of the structure in bytes.
	 */
	std::size_t totalSize() const;



	/**
	 * Add a ReflectionElement to this Reflection.
	 * The element's offset is expected to be relative to the current object.
	 */
	void add(ReflectionElement element);

	/**
	 * Add another Reflection to this one.
	 * All elements are added to the back.
	 */
	void add(Reflection& reflection);



	/**
	 * Test if this Reflection is equal to another one.
	 * Does a deep-comparison against the other reflection element.
	 */
	bool operator==(const Reflection& that) const;

	/**
	 * Test if this Reflection is equal to another StaticReflection.
	 * Does a deep-comparison against the other object.
	 */
	bool operator==(const StaticReflection& that) const;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
